package serverside;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author AbdallaEssam
 */
public class MyServer extends Thread {

    ServerSocket welcomeSocket;
    private static final int maxClientsCount = 10;
    private static final clientThread[] threads = new clientThread[maxClientsCount];
    DataOutputStream os;

    public MyServer() throws IOException {
        welcomeSocket = new ServerSocket(6789);
    }

    public void connect() {

        //System.out.println(welcomeSocket.getLocalSocketAddress());
        while (true) {
            try {
                Socket connectionSocket = welcomeSocket.accept();
                int i = 0;
                for (i = 0; i < maxClientsCount; i++) {
                    if (threads[i] == null) {
                        (threads[i] = new clientThread(connectionSocket, threads, i)).start();
                        System.out.println("client " + connectionSocket.getInetAddress() + " is connected");
                        break;
                    }
                }
                if (i == maxClientsCount) {
                    DataOutputStream os = new DataOutputStream(connectionSocket.getOutputStream());
                    os.writeBytes("Server too busy. Try later.");
                    os.close();
                    System.out.println("Client " + connectionSocket.getInetAddress()
                            + "is forced to leave because of trafic");
                    connectionSocket.close();
                }

            }//try
            catch (IOException e) {
                e.printStackTrace();
                break;
            }
        } //end while 
    }//end run

    private static class clientThread extends Thread {

        //class members 
        Socket clientConnectionSocket;
        String clientSentence = "null";
        String capitalizedSentence;
        BufferedReader inFromClient = null;
        DataOutputStream outToClient = null;
        clientThread[] myThreads;
        int index;
        ATM myATM = new ATM();
        int i = 0;
        int j = 0;

        public clientThread(Socket _connectionSocket, clientThread[] _threads, int _index) {
            clientConnectionSocket = _connectionSocket;
            myThreads = _threads;
            index = _index;
        }//end of constructor 

        public void run() {
            try {
                //clientConnectionSocket.setSoTimeout(5000);
                inFromClient = new BufferedReader(
                        new InputStreamReader(clientConnectionSocket.getInputStream()));
                outToClient = new DataOutputStream(
                        clientConnectionSocket.getOutputStream());
                // tell the client that he is connected to server 
                outToClient.writeBytes("You are connected to ATM server\n");

                clientSentence = inFromClient.readLine();

                System.out.println("client " + clientConnectionSocket.getInetAddress()
                        + " sent: " + clientSentence);
                i++;
                System.err.println("Entering While then switch for the " + i + " time");
                while (!clientSentence.equalsIgnoreCase("EXIT")) {
                    j++;
                    System.err.println("While loop no. " + j);
                    //System.out.println(clientSentence);
                    switch (clientSentence) {
                        case "LOGIN": {
                            String[] list;
                            outToClient.writeBytes("You can send password and PIN number.\n");
                            //may be if i check what comes from the next line, the 
                            //NullPointerException dissapear
                            clientSentence = inFromClient.readLine();
                            list = seprate(clientSentence);
                            System.out.println(list.toString());

                            //boolean flag = clientSentence.equals("1234,1234");
                            //System.out.println("flag is: " + flag);
                            myATM.authenticateUser(list[0], list[1]);
                            if (myATM.isUserAuthenticated()) /**/ {
                                outToClient.writeBytes("true\n");
                                System.out.println("Sent True");
                            } else {
                                outToClient.writeBytes("false\n");
                                System.out.println("Sent False");
                            }
                            break;
                        }
                        case "WITHDRAW": {
                            //if(myATM.isUserAuthenticated())
                            outToClient.writeBytes("You can withdraw.\n");
                            clientSentence = inFromClient.readLine();
                            System.out.println("FastCash: user sent: " + clientSentence);
                            String transactionResult = myATM.fastCash(clientSentence);
                            outToClient.writeBytes(transactionResult + "\n");
                            break;
                        }

                        case "FUNDTRANSFER": {
                            String[] list;
                            //prompt the client to send transaction data
                            //which is account number  and amount
                            outToClient.writeBytes("You can transfer.\n");
                            // get account number and amount from user in one
                            //string and seperate them
                            clientSentence = inFromClient.readLine();
                            System.out.println("TRANSFER: user sent: " + clientSentence);
                            list = seprate(clientSentence);
                            String transactionResult = myATM.Transfer(list[0], list[1]);

                            outToClient.writeBytes(transactionResult + "\n");
                            break;
                        }
                        case "BALANCEINQUIRY": {
                            outToClient.writeBytes("You can query.\n");
                            String result = myATM.balanceInquiry();
                            System.err.println("BALANCEINQUIRY: result is " + result);
                            outToClient.writeBytes(result + "\n");
                            break;
                        }
                        
                        case "BILLPAYMENT": {
                            String[] list;
                            outToClient.writeBytes("You can pay.\n");
                            // clientSentence will contain 4 arguments 
                            clientSentence = inFromClient.readLine();
                            System.out.println("BILLPAYMENT: user sent: " + clientSentence);
                            list = seprate(clientSentence);
                            String transactionResult = myATM.payBill(list[0], list[1], list[2], list[3]);
                            outToClient.writeBytes(transactionResult + "\n");
                            break;
                        }

                        case "CASHDEPOSIT": {
                            outToClient.writeBytes("You can deposit.\n");
                            // clientSentence will contain 4 arguments 
                            clientSentence = inFromClient.readLine();
                            System.out.println("CASHDEPOSIT: user sent: " + clientSentence);                            
                            String transactionResult = myATM.Deposit(clientSentence);
                            outToClient.writeBytes(transactionResult + "\n");
                            break;
                        }
                        default: {
                        }
                    }//end switch    
                                        
                    System.out.println("Waiting for next input from client... \n");
                    
                    clientSentence = inFromClient.readLine();
                    System.out.println("client " + clientConnectionSocket.getInetAddress()
                            + " sent: " + clientSentence);
                    if(clientSentence.equals(null))
                        break;
                }//end while
                //outToClient.writeBytes(capitalizedSentence); 

                inFromClient.close();
                outToClient.close();
                System.out.println("Client " + clientConnectionSocket.getInetAddress()
                        + "is leaving!");
                clientConnectionSocket.close();
                if (myThreads[index] != null) {
                    myThreads[index] = null;
                }
            } catch (SocketTimeoutException e) {
                System.out.println("Socket Timeout Exception\n");
                e.printStackTrace();
            } catch (NullPointerException e) {
//                try {
//                    //System.err.println("NullPointerException occure\n");
//                    //System.err.println("Be ready for input again, but please input write things\n");
//                    
//                    inFromClient.close();
//                    outToClient.close();
//                    System.out.println("Client " + clientConnectionSocket.getInetAddress()
//                            + "is leaving!");
//                    clientConnectionSocket.close();
//                    if (myThreads[index] != null) {
//                        myThreads[index] = null;
//                    }
//                } catch (IOException ex) {
//                    System.err.println("Error inside the catch of nullPointerException");
//                }
            } catch (Exception e) {
                System.out.println("Exception occure\n");
                e.printStackTrace();
                try {
                    inFromClient.close();
                    outToClient.close();
                    System.out.println("Client " + clientConnectionSocket.getInetAddress()
                            + "is leaving!");
                    clientConnectionSocket.close();
                    if (myThreads[index] != null) {
                        myThreads[index] = null;
                    }
                } catch (IOException ex) {
                    System.err.println("Error inside the catch Exceptions");
                }
            }

        }


        public static String[] seprate(String x) {
            int temp = 0;
            String[] str = new String[4];
            for (int i = 0; i < 4; i++) {
                str[i] = "";
            }
            for (char ch : x.toCharArray()) {

                if (ch == ',') {
                    temp++;
                    continue;
                }
                str[temp] = str[temp] + ch;
            }
            return str;
        }
    }//end class clientThread
}
